/*
 * Copyright (c) 2011 by Konstantin Pavlov.
 */

package gwtlx.html5.client.forms;

import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.TextBoxBase;
import gwtlx.html5.client.Browser;

/**
 * Html5Helper is a helper class dealing with html5 form elements.
 *
 * @author Konstantin Pavlov
 * @version $LastChangedRevision: 22 $
 * @since 09.01.11
 */
public abstract class Html5Helper {

    /** CSS class name assigned to form element when placeholder text is visible */
    private static String PLACEHOLDER_CLASS = "placeholder";

    private static FocusHandler placeholderFocusHandler;
    private static BlurHandler placeholderBlurHandler;

    /**
     * Returns singleton instance of BlurHandler intended for handling
     * focus events on fields with placeholder support
     *
     * @return a focus handler
     */
    private static FocusHandler getPlaceholderFocusHandler() {
        if (placeholderFocusHandler == null) {
            placeholderFocusHandler = new FocusHandler() {
                @Override
                public void onFocus(FocusEvent event) {
                    final TextBoxBase source = (TextBoxBase) event.getSource();
                    source.setValue(source.getElement().getPropertyString("realValue"));
                    source.removeStyleName(PLACEHOLDER_CLASS);
                }
            };
        }
        return placeholderFocusHandler;
    }

    /**
     * Returns singleton instance of BlurHandler intended for handling
     * blur events on fields with placeholder support
     *
     * @return a blur handler
     */
    private static BlurHandler getPlaceholderBlurHandler() {
        if (placeholderBlurHandler == null) {
            placeholderBlurHandler = new BlurHandler() {
                @Override
                public void onBlur(BlurEvent event) {
                    final TextBoxBase source = (TextBoxBase) event.getSource();
                    final Element element = source.getElement();
                    element.setPropertyString("realValue", source.getValue());
                    if (source.getValue().length() == 0) {
                        source.setValue(element.getAttribute("placeholder"));
                        source.addStyleName(PLACEHOLDER_CLASS);
                    }
                }
            };
        }
        return placeholderBlurHandler;
    }

    /**
     * Sets oplacaholder text value on specified textbox widget.
     * <p/>
     * If browser has native support of <code>placeholder</code> HTML5 attribute
     * then uses this feature, otherwise, attaches blur and focus handlers
     * to specified element (if these handlers have not been attached before).
     *
     * @param textBoxBase a widget to set placeholder text to
     * @param text        a text to set
     */
    public static void setPlaceholder(TextBoxBase textBoxBase, String text) {
        final Element element = textBoxBase.getElement();

        if (text != null && text.length() > 0 && !Browser.hasPlaceholderSupport()) {
            if (!element.hasAttribute("placeholder")) {
                // add handlers only once
                textBoxBase.addFocusHandler(getPlaceholderFocusHandler());
                textBoxBase.addBlurHandler(getPlaceholderBlurHandler());
            }
            if (textBoxBase.getValue().length() == 0) {
                textBoxBase.setValue(text);
                textBoxBase.addStyleName(PLACEHOLDER_CLASS);
            }
        }
        element.setAttribute("placeholder", text);
    }

    /**
     * Returns value of placeholder text for specified textbox widget.
     *
     * @param textBoxBase a widget to get placeholder text from
     *
     * @return value a placeholder text value or empty string
     *         if widget does not have placeholder text defined.
     */
    public static String getPlaceholder(TextBoxBase textBoxBase) {
        return textBoxBase.getElement().getAttribute("placeholder");
    }

    public static void setAutofocus(TextBoxBase textBoxBase, boolean autofocus) {
        textBoxBase.getElement().setPropertyBoolean("autofocus", autofocus);
    }

    /**
     * Returns value of <code>autofocus</code> property of given widget.
     *
     * @param textBoxBase a widget to get the property from
     *
     * @return true if aftofocus enabled for given widget
     */
    public static boolean isAutofocus(TextBoxBase textBoxBase) {
        return textBoxBase.getElement().getPropertyBoolean("autofocus");
    }

    public static void setRequired(TextBoxBase textBoxBase, boolean required) {
        if (required) {
            textBoxBase.getElement().setAttribute("required", "required");
        } else {
            textBoxBase.getElement().removeAttribute("required");
        }
    }

    public static boolean isRequired(TextBoxBase textBoxBase) {
        return textBoxBase.getElement().hasAttribute("required");
    }


    public static void setNovalidate(FormPanel form, boolean required) {
        if (required) {
            form.getElement().setAttribute("novalidate", "novalidate");
        } else {
            form.getElement().removeAttribute("novalidate");
        }
    }

    public static void setNumericAttribute(TextBoxBase textBoxBase,
                                           String name, Number min) {
        if (min != null) {
            textBoxBase.getElement().setAttribute(name, min.toString());
        } else {
            textBoxBase.getElement().removeAttribute(name);
        }
    }

    public static Double getNumericAttribute(TextBoxBase textBoxBase,
                                             String name) {
        final String str = textBoxBase.getElement().getAttribute(name);
        if (str != null) {
            try {
                return Double.parseDouble(str);
            } catch (NumberFormatException e) {
                return null;
            }
        } else {
            return null;
        }
    }
}
